package cn.edu.scau.sec.rw.model.pro_manage.simulation;

import cn.edu.scau.sec.rw.model.disk_file.utils.ExeUtil;
import cn.edu.scau.sec.rw.model.pro_manage.Process;

/**
 * 模拟CPU
 */
public class CPU {

    private Process process;
    private Register register;
    private static CPU cpu = null;
    private CPU() {}
    public static CPU getCpu() {
        if ((cpu == null)) {
            cpu = new CPU();
        }
        return cpu;
    }

    /**
     * 判断是否有中断，0表示没有中断
     * @param PSW
     * @return
     */
    public boolean checkInterrupt (Integer[] PSW) {
//        return (register.getPSW()[0] == 0?false:true);
        if (PSW[0] == 1) return true;
        if (PSW[1] == 1) return true;
        if (PSW[2] == 1) return true;

        return false;
    }

    /**
     * 执行可执行文件的指令，根据进程控制块中的PC值执行对应的指令
     * @param
     */
    public void execute() {
        process = Process.getReadyProcesses().remove(0);
        process.getPCB().setProState("运行");
        register = process.getPCB().getRegister();  //将这个进程的 PCB 中记录的各寄存器内容恢复到 CPU 各个寄存器内（恢复现场）
        int x = register.getAX();
        int PC = register.getPC();
        int slice = process.getClock().getRelativeClock();
        //根据时间片大小依次执行
        try {
            while (slice > 0) {
                if (!checkInterrupt(register.getPSW())) {
                    System.out.println("进程号" + process.getPCB().getProId());
                    String stringIR = register.getIR().get(PC++);
                    x = ExeUtil.execute(this, x, stringIR);  //执行指令
                    slice--;
                    //update(process, register, x, PC, slice);

                    update(process, register, x, PC, slice);   //执行中断
                    if (register.getPSW()[0] == 1) {
                        Interrupt.programInterrupt(process);
                        process = null;
                        break;
                    } else if (register.getPSW()[2] == 1) {
                        Interrupt.IOInterrupt(process);
                        break;
                    }
                    Thread.sleep(1000 * 2);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (slice == 0 && (register.getPC() < register.getIR().size()-1)) {
            register.getPSW()[1] = 1;
            update(process, register, x, PC, slice);
            Interrupt.timeSliceInterrupt(process);
            process = null;
        }
    }

    public void executeFree() {
        try {
            System.out.println("执行空闲进程");
            Thread.sleep(1000 * 2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 刷新CPU寄存器值和时间片
     * @param process
     * @param register
     * @param x
     * @param pc
     * @param slice
     */
    public void update(Process process, Register register, int x, int pc, int slice) {
        register.setAX(x);
        register.setPC(pc);
        process.getClock().setRelativeClock(slice);
    }

    public Process getProcess() {
        return process;
    }

    public void setProcess(Process process) {
        this.process = process;
    }

    public Register getRegister() {
        return register;
    }

    public void setRegister(Register register) {
        this.register = register;
    }

}
